package org.schrag.sbbdroid;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.schrag.sbbdroid.data.Connection;
import org.schrag.sbbdroid.data.Connections;
import org.schrag.sbbdroid.data.Part;
import org.schrag.sbbdroid.data.SBBResponse;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

import android.util.Log;

public class SBBResponseHandler extends DefaultHandler {

	// ===================================================================================
	// Fields
	// ===================================================================================
	private boolean isin_connection = false;
	private boolean isin_part = false;
	private boolean isin_from = false;
	private boolean isin_to = false;
	private boolean isin_durationinfo = false;
	private boolean isin_comment = false;
	private boolean isin_type = false;
	private boolean isin_train = false;
	private boolean isin_url = false;

	private DateFormat formatter = new SimpleDateFormat("dd.MM.yy hh:mm");

	private Connection currentConnection = null;
	private Part currentPart = null;

	private SBBResponse myParsedSBBResponse;

	public SBBResponseHandler(SBBResponse myResponse) {
		this.myParsedSBBResponse = myResponse;
	}

	@Override
	public void startElement(String namespacesURI, String localName,
			String qName, Attributes atts) throws SAXException {
		if (localName.equals("connections")) {
			this.myParsedSBBResponse.setConnections(new Connections());
			this.myParsedSBBResponse.getConnections().setIdent(
					atts.getValue("ident"));
		} else if (localName.equals("connection")) {
			this.isin_connection = true;
			this.currentConnection = new Connection();
			this.currentConnection.setDuration(atts.getValue("duration"));
			this.currentConnection.setChangeTrack(atts.getValue("changeTrack"));
			try {
				this.currentConnection.setStartTime(formatter.parse(atts
						.getValue("datestart")
						+ " " + atts.getValue("timestart")));
				this.currentConnection.setEndTime(formatter.parse(atts
						.getValue("dateend")
						+ " " + atts.getValue("timeend")));
			} catch (ParseException e) {
				Log.e("SBBIphoneHandler", "error while parsing start/end", e);
			}
		} else if (localName.equals("part")) {
			this.isin_part = true;
			this.currentPart = new Part();
			this.currentPart.setTrackStart(atts.getValue("trackstart"));
			this.currentPart.setTrackEnd(atts.getValue("trackend"));
			this.currentPart.setTrackStart(atts.getValue("trackstart"));
			this.currentPart.setTrackEnd(atts.getValue("trackend"));
			try {
				this.currentPart.setStart(formatter.parse(atts
						.getValue("datestart")
						+ " " + atts.getValue("timestart")));
				this.currentPart.setEnd(formatter.parse(atts
						.getValue("dateend")
						+ " " + atts.getValue("timeend")));
			} catch (ParseException e) {
				Log.e("SBBIphoneHandler", "error while parsing start/end", e);
			}
		} else if (localName.equals("from")) {
			this.isin_from = true;
		} else if (localName.equals("to")) {
			this.isin_to = true;
		} else if (localName.equals("durationinfo")) {
			this.isin_durationinfo = true;
		} else if (localName.equals("comment")) {
			this.isin_comment = true;
		} else if (localName.equals("type")) {
			this.isin_type = true;
		} else if (localName.equals("train")) {
			this.isin_train = true;
		} else if (localName.equals("url")) {
			this.isin_url = true;
		}
		// Log.v("SBBIphoneHandler","<"+localName+">");
	}

	@Override
	public void endElement(String namespaceURL, String localName, String qName)
			throws SAXException {
		if (localName.equals("connection")) {
			this.myParsedSBBResponse.getConnections().getConnections().add(
					this.currentConnection);
			this.currentConnection = null;
			this.isin_connection = false;
		} else if (localName.equals("part")) {
			this.currentConnection.getParts().add(this.currentPart);
			this.currentPart = null;
			this.isin_part = false;
		} else if (localName.equals("from")) {
			this.isin_from = false;
		} else if (localName.equals("to")) {
			this.isin_to = false;
		} else if (localName.equals("durationinfo")) {
			this.isin_durationinfo = false;
		} else if (localName.equals("comment")) {
			this.isin_comment = false;
		} else if (localName.equals("type")) {
			this.isin_type = false;
		} else if (localName.equals("train")) {
			this.isin_train = false;
		} else if (localName.equals("url")) {
			this.isin_url = false;
		}
		// Log.v("SBBIphoneHandler","</"+localName+">");
	}

	@Override
	public void characters(char ch[], int start, int length) {
		if (this.isin_connection && !this.isin_part && this.isin_from) {
			this.currentConnection.setFrom(new String(ch, start, length));
		} else if (this.isin_connection && !this.isin_part && this.isin_to) {
			this.currentConnection.setTo(new String(ch, start, length));
		} else if (this.isin_connection && !this.isin_part
				&& this.isin_durationinfo) {
			this.currentConnection
					.setDurationInfo(new String(ch, start, length));
		} else if (this.isin_connection && this.isin_part && this.isin_from) {
			this.currentPart.setFrom(new String(ch, start, length));
		} else if (this.isin_connection && this.isin_part && this.isin_to) {
			this.currentPart.setTo(new String(ch, start, length));
		} else if (this.isin_connection && this.isin_part && this.isin_comment) {
			this.currentPart.setComment(new String(ch, start, length));
		} else if (this.isin_connection && this.isin_part && this.isin_type) {
			this.currentPart.setType(new String(ch, start, length));
		} else if (this.isin_connection && this.isin_part && this.isin_train) {
			this.currentPart.setTrain(new String(ch, start, length));
		} else if (this.isin_connection && this.isin_part && this.isin_url) {
			this.currentPart.setInfoUrl(URLDecoder.decode(new String(ch, start, length)));
		}
		// Log.v("SBBIphoneHandler",new String(ch, start, length));
	}

	@Override
	public void startDocument() throws SAXException {
		Log.i("SBBResponseHandler", "start doc");
	}

	@Override
	public void endDocument() throws SAXException {
		Log.i("SBBResponseHandler", "end doc");
	}

	public SBBResponse getParsedData() {
		return this.myParsedSBBResponse;
	}

	static public SBBResponse getResponse(String from, String to, String via,
			Date time, boolean is_timeStart) {
		return getResponse(from, to, via, time, is_timeStart, true, true, true,
				true, true, true, true, true, true, true);
	}

	static public SBBResponse getResponse(String from, String to, String via,
			Date time, boolean is_timeStart, boolean use_icetgv,
			boolean use_ecic, boolean use_ir, boolean use_drx,
			boolean use_schiff, boolean use_sreg, boolean use_bus,
			boolean use_seilbahn, boolean use_arzex, boolean use_tram) {
		try {

			String s_url = "http://sbbiphone.ch/v250?l=d&&start=1&iv=sbb1";
			s_url += "&S=" + URLEncoder.encode(from);
			s_url += "&Z=" + URLEncoder.encode(to);
			s_url += "&V1=" + (via == null ? "" : URLEncoder.encode(via));
			s_url += "&ti=" + (((double) time.getTime()) / 1000);
			s_url += "&tm=" + (is_timeStart ? "1" : "0");
			s_url += "&P0=" + (use_icetgv ? "1" : "0");
			s_url += "&P1=" + (use_ecic ? "1" : "0");
			s_url += "&P2=" + (use_ir ? "1" : "0");
			s_url += "&P3=" + (use_drx ? "1" : "0");
			s_url += "&P4=" + (use_schiff ? "1" : "0");
			s_url += "&P5=" + (use_sreg ? "1" : "0");
			s_url += "&P6=" + (use_bus ? "1" : "0");
			s_url += "&P7=" + (use_seilbahn ? "1" : "0");
			s_url += "&P8=" + (use_arzex ? "1" : "0");
			s_url += "&P9=" + (use_tram ? "1" : "0");

			return getResponse(s_url);

		} catch (Exception e) {
			Log.e("TimetableSearchActivity", "SBB Query Error", e);
			return null;
		}
	}

	static public SBBResponse getResponse(String s_url) {
		SBBResponse myResponse = new SBBResponse();

		try {
			Log.i("TimetableSearchActivity", "getting url: " + s_url);
			
			/* Create a URL we want to load some xml-data from. */
			URL url = new URL(s_url);

			/* Get a SAXParser from the SAXPArserFactory. */
			SAXParserFactory spf = SAXParserFactory.newInstance();
			SAXParser sp = spf.newSAXParser();

			/* Get the XMLReader of the SAXParser we created. */
			XMLReader xr = sp.getXMLReader();
			/* Create a new ContentHandler and apply it to the XML-Reader */
			SBBResponseHandler mySBBHandler = new SBBResponseHandler(myResponse);
			xr.setContentHandler(mySBBHandler);

			/* Parse the xml-data from our URL. */
			xr.parse(new InputSource(url.openStream()));
			/* Parsing has finished. */

			/* Our ExampleHandler now provides the parsed data to us. */
			myResponse = mySBBHandler.getParsedData();

		} catch (MalformedURLException e) {
			Log.e("TimetableSearchActivity", "SBB Query Error", e);
		} catch (ParserConfigurationException e) {
			Log.e("TimetableSearchActivity", "SBB Query Error", e);
		} catch (SAXException e) {
			Log.e("TimetableSearchActivity", "SBB Query Error", e);
		} catch (IOException e) {
			Log.e("TimetableSearchActivity", "SBB Query Error", e);
		} finally {
			return myResponse;
		}
	}

}
